//
// Created by chizuru on 2025/10/11.
//

#include "SensorTPApplication.h"
#include "libserialport.h"
#include "ProtocolCodecFactory.h"
#include "OperationResult.h"
#include "SerialPortAdapter.h"
#include "ReconnectDecorator.h"
#include "LoggingDecorator.h"
#include "DeviceComm.h"
#include "SensorTPDevice.h"
#include "SensorTPService.h"
#include "ConnectivityMonitor.h"

SensorTPApplication::~SensorTPApplication() {
    monitor->stop();
    adapter->close();
}

OperationResult SensorTPApplication::isConnected() {
    if (!adapter) {
        return OperationResult::Fail(ErrorCode::Unknown, "Adapter is NULL");
    }
    if (!adapter->isConnected()) {
        return OperationResult::Fail(ErrorCode::Unknown, "Device Not Found");
    }
    return OperationResult::Ok();
}

OperationResult SensorTPApplication::connect(const std::string &com) {
    try{
        adapter = std::make_shared<SerialPortAdapter>(com);
        auto ok = adapter->connect();
        if (!ok.success) {
            return ok;
        }
        adapter->configure(9600, 8, SP_PARITY_NONE, 1, SP_FLOWCONTROL_NONE);

        return OperationResult::Ok();
    } catch (std::exception& e) {
        return OperationResult::Fail(ErrorCode::Unknown, e.what());
    }

}

OperationResult SensorTPApplication::close() {
    try {
        if (!adapter) {
            return OperationResult::Fail(ErrorCode::Unknown, "Adapter is NULL");
        }
        stopListening();
        if (monitor) {
            monitor->stop();
        }
        return adapter->close();
    }catch (std::exception& e) {
        return OperationResult::Fail(ErrorCode::Unknown, e.what());
    }
}

OperationResult SensorTPApplication::initialize() {
    try {
        if (!adapter) {
            return OperationResult::Fail(ErrorCode::Unknown, "Adapter is NULL");
        }
        reconnectDecorator = std::make_shared<ReconnectDecorator>(adapter);
        loggingDecorator = std::make_shared<LoggingDecorator>(reconnectDecorator);

        comm = std::make_shared<DeviceComm>(*loggingDecorator);
        device = std::make_shared<SensorTPDevice>(*comm, ProtocolCodecFactory::instance().create("modbus_default"));
        service = std::make_shared<SensorTPService>(*device, std::make_shared<TinyXmlRegisterTPMap>("DevSupport/resource/tp_sensor_regs_generated.xml"));
        auto ok = service->checkIfHasSensorConnected();
        if (!ok.success) {
            return ok;
        }
        ok = service->initSlaveAddress();
        if (!ok.success) {
            return ok;
        }
        ok = service->batchSetInitRegisters();
        if (!ok.success) {
            return ok;
        }

        auto checkFunc = [&]() { return adapter->isConnected(); };
        auto observer = [](bool connected){
            std::cerr << "Device connected: " << (connected ? "YES":"NO") << "\n";
        };
        monitor = std::make_shared<ConnectivityMonitor>(checkFunc, observer);
        monitor->start();
        return OperationResult::Ok();
    } catch (std::exception& e) {
        return OperationResult::Fail(ErrorCode::Unknown, e.what());
    }
}

void SensorTPApplication::startListening() {
    bool expected = false;
    if (!running.compare_exchange_strong(expected, true))
        return;
    worker = std::thread([this](){
        while (running) {
            float t;
            service->getTemperature(t);
            float p;
            service->getPressure(p);

            this->t.store(t);
            this->p.store(p);

            std::unique_lock lk(mtx);
            cv.wait_for(lk, interval, [this]{ return !running.load(); });
        }
    });
}

void SensorTPApplication::stopListening() {
    bool expected = true;
    if (!running.compare_exchange_strong(expected, false))
        return;
    cv.notify_all();
    if (worker.joinable())
        worker.join();
}

const float SensorTPApplication::getT() const {
    return t.load();
}

const float SensorTPApplication::getP() const {
    return p.load();
}
